package org.zhengquan.service;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.zhengquan.dao.SysAclMapper;
import org.zhengquan.dao.SysAclModuleMapper;
import org.zhengquan.dao.SysDeptMapper;
import org.zhengquan.dto.AclDto;
import org.zhengquan.dto.AclModuleLevelDto;
import org.zhengquan.dto.DeptLevelDto;
import org.zhengquan.pojo.SysAcl;
import org.zhengquan.pojo.SysAclModule;
import org.zhengquan.pojo.SysDept;
import org.zhengquan.util.LevelUtil;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhengquan
 * @date 2017/10/27
 */
@Service
public class SysTreeService {
    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private SysAclModuleMapper sysAclModuleMapper;

    @Autowired
    private SysCoreService sysCoreService;

    @Autowired
    private SysAclMapper sysAclMapper;

    public List<AclModuleLevelDto> userAclTree(Integer userId){
        List<SysAcl> userAclList = sysCoreService.selectUserAclList(userId);
        List<AclDto> aclDtoList = Lists.newArrayList();
        for (SysAcl sysAcl : userAclList) {
            AclDto aclDto = AclDto.adapt(sysAcl);
            aclDto.setHasAcl(true);
            aclDto.setChecked(true);
            aclDtoList.add(aclDto);
        }
        return aclListToTree(aclDtoList);
    }

    public List<AclModuleLevelDto> roleTree(int roleId) {
        //当前用户已分配过的权限点
        List<SysAcl> curUserAclList = sysCoreService.selectCurUserAclList();
        //当前角色分配的权限点
        List<SysAcl> curRoleAclList = sysCoreService.selectRoleAclList(roleId);
        //当前所有权限点
        List<SysAcl> allAclList = sysAclMapper.selectAllAcl();

        Set<Integer> userAclIdSet = curUserAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());
        Set<Integer> roleAclIdSet = curRoleAclList.stream().map(sysAcl -> sysAcl.getId()).collect(Collectors.toSet());

        List<AclDto> aclDtoList = Lists.newArrayList();

        for (SysAcl sysAcl : allAclList) {
            AclDto aclDto = AclDto.adapt(sysAcl);
            if (userAclIdSet.contains(aclDto.getId())) {
                aclDto.setHasAcl(true);
            }
            if (roleAclIdSet.contains(aclDto.getId())) {
                aclDto.setChecked(true);
            }
            aclDtoList.add(aclDto);
        }
        return aclListToTree(aclDtoList);
    }

    public List<DeptLevelDto> deptTree() {
        List<SysDept> sysDeptList = sysDeptMapper.selectAllDept();

        List<DeptLevelDto> deptLevelDtoList = Lists.newArrayList();
        for (SysDept sysDept : sysDeptList) {
            DeptLevelDto deptLevelDto = DeptLevelDto.adapt(sysDept);
            deptLevelDtoList.add(deptLevelDto);
        }

        return deptListToTree(deptLevelDtoList);
    }

    public List<AclModuleLevelDto> aclModuleTree() {
        List<SysAclModule> sysAclModuleList = sysAclModuleMapper.selectAllAclModule();

        List<AclModuleLevelDto> aclModuleLevelDtoList = Lists.newArrayList();
        for (SysAclModule sysAclModule : sysAclModuleList) {
            AclModuleLevelDto aclModuleLevelDto = AclModuleLevelDto.adapt(sysAclModule);
            aclModuleLevelDtoList.add(aclModuleLevelDto);
        }

        return aclModuleListToTree(aclModuleLevelDtoList);
    }


    private List<AclModuleLevelDto> aclListToTree(List<AclDto> aclDtoList) {
        if (CollectionUtils.isEmpty(aclDtoList)) {
            return Lists.newArrayList();
        }
        List<AclModuleLevelDto> aclModuleList = aclModuleTree();
        Multimap<Integer, AclDto> moduleIdAclMap = ArrayListMultimap.create();
        for (AclDto aclDto : aclDtoList) {
            if (aclDto.getState() == 1) {
                moduleIdAclMap.put(aclDto.getAclModuleId(), aclDto);
            }
        }
        bindAclsWithOrder(aclModuleList, moduleIdAclMap);
        return aclModuleList;
    }

    public void bindAclsWithOrder(List<AclModuleLevelDto> aclModuleList, Multimap<Integer, AclDto> moduleIdAclMap) {
        if (CollectionUtils.isEmpty(aclModuleList)) {
            return;
        }
        for (AclModuleLevelDto aclModuleLevelDto : aclModuleList) {
            List<AclDto> aclDtoList = (List<AclDto>) moduleIdAclMap.get(aclModuleLevelDto.getId());
            if (CollectionUtils.isNotEmpty(aclDtoList)) {
                Collections.sort(aclDtoList, aclSeqComparator);
                aclModuleLevelDto.setAclList(aclDtoList);
            }
            bindAclsWithOrder(aclModuleLevelDto.getList(), moduleIdAclMap);
        }
    }

    private List<DeptLevelDto> deptListToTree(List<DeptLevelDto> srcList) {
        if (CollectionUtils.isEmpty(srcList)) {
            return Lists.newArrayList();
        }
        //level -> [dept1,dept2 ...]
        Multimap<String, DeptLevelDto> levelDeptMap = ArrayListMultimap.create();
        List<DeptLevelDto> rootList = Lists.newArrayList();

        for (DeptLevelDto deptLevelDto : srcList) {
            levelDeptMap.put(deptLevelDto.getLevel(), deptLevelDto);
            if (LevelUtil.ROOT.equals(deptLevelDto.getLevel())) {
                rootList.add(deptLevelDto);
            }
        }
        //按照seq从小到大排序
        Collections.sort(rootList, deptSeqComparator);
        //递归生成树
        transformDeptTree(srcList, LevelUtil.ROOT, levelDeptMap);
        return rootList;
    }

    private List<AclModuleLevelDto> aclModuleListToTree(List<AclModuleLevelDto> srcList) {
        if (CollectionUtils.isEmpty(srcList)) {
            return Lists.newArrayList();
        }
        //level -> [dept1,dept2 ...]
        Multimap<String, AclModuleLevelDto> levelAclModuleMap = ArrayListMultimap.create();
        List<AclModuleLevelDto> rootList = Lists.newArrayList();

        for (AclModuleLevelDto aclModuleLevelDto : srcList) {
            levelAclModuleMap.put(aclModuleLevelDto.getLevel(), aclModuleLevelDto);
            if (LevelUtil.ROOT.equals(aclModuleLevelDto.getLevel())) {
                rootList.add(aclModuleLevelDto);
            }
        }
        //按照seq从小到大排序
        Collections.sort(rootList, aclModuleSeqComparator);
        //递归生成树
        transformAclModuleTree(srcList, LevelUtil.ROOT, levelAclModuleMap);
        return rootList;
    }

    private void transformDeptTree(List<DeptLevelDto> deptLevelDtoList, String level, Multimap<String, DeptLevelDto> levelDeptMap) {
        //遍历当前的元素
        for (DeptLevelDto deptLevelDto : deptLevelDtoList) {
            //处理当前的层级
            String nextLevel = LevelUtil.calculateLevel(level, deptLevelDto.getId());
            //处理下一层
            List<DeptLevelDto> tempDeptLevelDtoList = (List<DeptLevelDto>) levelDeptMap.get(nextLevel);
            if (CollectionUtils.isNotEmpty(tempDeptLevelDtoList)) {
                //按照seq从小到大排序
                Collections.sort(tempDeptLevelDtoList, deptSeqComparator);
                //设置进一层部门
                deptLevelDto.setList(tempDeptLevelDtoList);
                //进入下一层处理
                transformDeptTree(tempDeptLevelDtoList, nextLevel, levelDeptMap);
            }

        }
    }

    private void transformAclModuleTree(List<AclModuleLevelDto> aclModuleLevelDtoList, String level, Multimap<String, AclModuleLevelDto> levelAclModuleMap) {
        //遍历当前的元素
        for (AclModuleLevelDto aclModuleLevelDto : aclModuleLevelDtoList) {
            //处理当前的层级
            String nextLevel = LevelUtil.calculateLevel(level, aclModuleLevelDto.getId());
            //处理下一层
            List<AclModuleLevelDto> tempAclModuleLevelDtoList = (List<AclModuleLevelDto>) levelAclModuleMap.get(nextLevel);
            if (CollectionUtils.isNotEmpty(tempAclModuleLevelDtoList)) {
                //按照seq从小到大排序
                Collections.sort(tempAclModuleLevelDtoList, aclModuleSeqComparator);
                //设置进一层模块
                aclModuleLevelDto.setList(tempAclModuleLevelDtoList);
                //进入下一层处理
                transformAclModuleTree(tempAclModuleLevelDtoList, nextLevel, levelAclModuleMap);
            }

        }
    }

    private Comparator<DeptLevelDto> deptSeqComparator = new Comparator<DeptLevelDto>() {
        @Override
        public int compare(DeptLevelDto o1, DeptLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };


    private Comparator<AclModuleLevelDto> aclModuleSeqComparator = new Comparator<AclModuleLevelDto>() {
        @Override
        public int compare(AclModuleLevelDto o1, AclModuleLevelDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };

    private Comparator<AclDto> aclSeqComparator = new Comparator<AclDto>() {
        @Override
        public int compare(AclDto o1, AclDto o2) {
            return o1.getSeq() - o2.getSeq();
        }
    };
}
